import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { V2Apply } from "./v2.apply.entity";
import { Repository } from "typeorm";
import { V2ApplyWorkflow, WorkflowType } from "./v2.apply.workflow.entity";
import { ApplyUserStatus, V2ApplyLog } from "./v2.apply.log.entity";
import { DeptRoleEnum, RoleEnum } from "src/role/role.enum";
import { UserSys } from "src/user/userSys.entity";
import { Forbidden, Http, NotFound } from "src/util/http";
import * as moment from "moment"
import { AttendanceService } from "src/attendance/attendance.service";
import { DepartService } from "src/depart/depart.service";
import { TimeResultType } from "src/attendance/attendance.entity";
import { UserService } from "src/user/user.service";
export const WorkflowData = {
    请假申请: [
        { type: WorkflowType.user, value: RoleEnum.manager },
        { type: WorkflowType.dept, value: DeptRoleEnum.personnel },
        { type: WorkflowType.user, value: RoleEnum.director },
        { type: WorkflowType.user, value: RoleEnum.boos },
    ],
    离职申请: [
        { type: WorkflowType.dept, value: DeptRoleEnum.personnel },
        { type: WorkflowType.user, value: RoleEnum.director },
        { type: WorkflowType.user, value: RoleEnum.boos },
    ],
}

@Injectable()
export class V2ApplyService {
    constructor(
        @InjectRepository(V2Apply)
        public readonly apply: Repository<V2Apply>,
        @InjectRepository(V2ApplyWorkflow)
        public readonly workflow: Repository<V2ApplyWorkflow>,
        @InjectRepository(V2ApplyLog)
        public readonly applylog: Repository<V2ApplyLog>,
        private readonly attendanceService: AttendanceService,
        private readonly departService: DepartService,
        private readonly userService: UserService
    ) {
        this.init()
    }

    public async finish(apply: V2Apply) {
        const data = JSON.parse(apply.data)
        if (apply.name === "请假申请") {
            const start = moment(data.start);
            const end = moment(data.end);
            while (start.isBefore(end)) {
                this.attendanceService.set(
                    apply.user,
                    start.format("YYYY-MM-DD hh:mm:ss"),
                    TimeResultType.Furlough,
                    TimeResultType.Furlough,
                    apply.comment
                )
                start.add(1, "day")
            }
        }
        if (apply.name === "离职申请") {
            await this.departService.create(
                apply.user,
                data.extraTime,
                data.reason,
                apply.comment
            )
        }
        const exist = await this.applylog.exist({
            where: {
                apply: {
                    id: apply.id
                },
                workUser: {
                    role: RoleEnum.boos
                }
            }
        })
        if (!exist) {
            await this.applylog.save(
                this.applylog.create({
                    apply,
                    workUser: await this.userService.userSys.findOne({
                        where: {
                            role: RoleEnum.boos
                        }
                    }),
                    status: ApplyUserStatus.已通过,
                    user: apply.user,
                    data: apply.data,
                    comment: apply.comment,
                    name: apply.name,
                    system: apply.system,
                    createAt: apply.createAt
                })
            )
        }

    }
    public async create(name: string, user: UserSys, data: any, comment: string) {
        const lists = await this.workflow.find({ where: { name }, relations: ["next"] });
        if (user.role === RoleEnum.boos) throw Http.forbidden("boos不能添加申请")
        if (!lists.length) throw NotFound
        const tree = this.list2tree(lists)
        let node = tree;
        let deptRole = user.dept?.deptRole;
        //特殊部门申请=人事。
        if ([DeptRoleEnum.administration, DeptRoleEnum.business, DeptRoleEnum.finance, DeptRoleEnum].some(e => e == deptRole)) {
            deptRole = DeptRoleEnum.personnel
        }
        while (node) {
            if (node.type === WorkflowType.user) {
                if (user.role === node.userRole) {
                    node = node.next;
                    if (!node) throw Forbidden
                    break;
                }
            } else if (deptRole === node.deptRole) {
                node = node.next;
                if (!node) throw Forbidden
                break
            }
            node = node.next;
        }
        const entity = this.apply.create({
            name,
            user,
            system: user.system,
            data,
            comment
        })
        entity.current = node || tree;
        await this.apply.save(entity);
        return await this.applylog.save(this.applylog.create({
            workflow: entity.current,
            apply: entity,
            name,
            user,
            comment,
            data,
            system: entity.system
        }))
    }

    private async init() {
        for (const name in WorkflowData) {
            const entity = await this.workflow.find({ where: { name }, relations: ["next"] });
            const list = WorkflowData[name];
            const tree = this.list2tree(entity)
            await this.save(name, tree, list);
        }
    }
    public list2tree(workflow: V2ApplyWorkflow[]) {
        const map = new Map();
        for (const item of workflow) {
            map.set(item.next?.id, item)
        }
        let head: V2ApplyWorkflow;
        while (map.size !== 0) {
            const node = map.get(head?.id);
            node.next = head;
            map.delete(head?.id)
            head = node;
        }
        return head;
    }
    private async save(name, tree: V2ApplyWorkflow, list: any[]) {
        const map = new Map();
        let head = tree;
        while (!!head) {
            map.set(head.id, head);
            head = head.next;
        }
        let target: V2ApplyWorkflow;
        for (const { type, value } of list) {
            const node = tree || this.workflow.create({ name });
            map.delete(node.id)
            node.deptRole = null
            node.userRole = null
            node.type = type;
            if (type === WorkflowType.dept) node.deptRole = value;
            else node.userRole = value
            await this.workflow.save(node);
            tree = tree?.next
            if (!!target) {
                target.next = node;
                await this.workflow.save(target);
            }
            target = node;
        }
        if (!!target) {
            target.next = null;
            await this.workflow.save(target);
        }
        map.forEach((value, key) => {
            console.log(key)
            this.workflow.delete(key)
        })
    }
}